package cc.autoapi.pucong.auto.flow.persistence.repository.node;


import cc.autoapi.pucong.auto.flow.persistence.po.node.NodeInfoPo;
import cc.autoapi.pucong.auto.flow.persistence.utils.jdbc.DatabaseUtils;
import cn.hutool.script.ScriptUtil;
import com.alibaba.fastjson2.JSONObject;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.task.extend.AbstractScriptTask;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.task.extend.ExtendTaskInstance;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.utils.JythonUtils;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.python.core.PyDictionary;
import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author pucong
 * @description 节点信息 service 实现类
 * @create 2024-09-23
 */
@Service
@Slf4j
public class NodeInfoServiceImpl implements NodeInfoService {

    @Override
    public void deleteByGroupIds(List<String> groupIds) {
        if (groupIds == null || groupIds.size() < 1) {
            return;
        }
        StringBuffer sqlBf = new StringBuffer();
        sqlBf.append("delete from auto_flow_node_info where group_id in (");
        for (int i = 0; i < groupIds.size(); i++) {
            sqlBf.append("?,");
        }
        sqlBf.deleteCharAt(sqlBf.length() - 1);
        sqlBf.append(")");
        List<Object> params = new ArrayList<>();
        params.addAll(groupIds);

        DatabaseUtils.execSql(params, sqlBf.toString(), Integer.class);
    }

    @Override
    public Object javaExeTest(String nodeScript, JSONObject jsonObjectParams) {
        AbstractScriptTask task = ExtendTaskInstance.getTask(nodeScript);
        JSONObject result = task.handle(jsonObjectParams);
        return result;
    }


    @Override
    public Object jsExeTest(String jsScript2, JSONObject jsonObjectParams) {
        Object run = ScriptUtil.invoke(jsScript2, "run", jsonObjectParams);
        Object json = null;
        if (run instanceof ScriptObjectMirror) {
            ScriptObjectMirror res = (ScriptObjectMirror) run;
            Object object = jsObjtoJavaObject(res);
            json = object;
        } else {
            json = run;
        }
        return json;
    }


    private Object jsObjtoJavaObject(ScriptObjectMirror mirror) {
        if (mirror.isEmpty()) {
            return null;
        }
        if (mirror.isArray()) {
            List<Object> list = new ArrayList<>();
            for (Map.Entry<String, Object> entry : mirror.entrySet()) {
                Object result = entry.getValue();
                if (result instanceof ScriptObjectMirror) {
                    list.add(jsObjtoJavaObject((ScriptObjectMirror) result));
                } else {
                    list.add(result);
                }
            }
            return list;
        }

        Map<String, Object> map = new HashMap<>(16);
        for (Map.Entry<String, Object> entry : mirror.entrySet()) {
            Object result = entry.getValue();
            if (result instanceof ScriptObjectMirror) {
                map.put(entry.getKey(), jsObjtoJavaObject((ScriptObjectMirror) result));
            } else {
                map.put(entry.getKey(), result);
            }
        }
        return map;
    }

    @Override
    public Object pythonExeTest(String python2, Map<PyObject, PyObject> mapObjectParams) {
        // 执行
        PyObject pyobj = null;
        try (PythonInterpreter interpreter = new PythonInterpreter()) {
            interpreter.exec(python2);

            // 第一个参数为期望获得的函数（变量）的名字，第二个参数为期望返回的对象类型
            PyFunction pyFunction = interpreter.get("run", PyFunction.class);
            //调用函数，如果函数需要参数，在Java中必须先将参数转化为对应的“Python类型”
            pyobj = pyFunction.__call__(new PyDictionary(mapObjectParams));
        }

        Object json = JythonUtils.toObjectFromPyObject(pyobj);
        return json;
    }

    @Override
    public List<NodeInfoPo> list(int whetherEnable) {
        List<Object> params = new ArrayList<>();
        StringBuffer sqlBf = new StringBuffer();
        sqlBf.append("select * from auto_flow_node_info where 1=1 and whether_enable = ? order by node_name asc");
        params.add(whetherEnable);
        List<NodeInfoPo> apiInfoPos = DatabaseUtils.execQueryListSql(params, sqlBf.toString(), NodeInfoPo.class);
        return apiInfoPos;
    }

    @Override
    public Boolean save(NodeInfoPo nodeInfo) {
        DatabaseUtils.saveAuto("auto_flow_node_info", nodeInfo);
        return true;
    }

    @Override
    public Boolean updateById(NodeInfoPo nodeInfoUpdate) {
        DatabaseUtils.updateAutoById("auto_flow_node_info", nodeInfoUpdate);
        return true;
    }

    @Override
    public Boolean removeBatchByIds(List<String> ids) {
        if (ids == null || ids.size() < 1) {
            return false;
        }
        StringBuffer sqlBf = new StringBuffer();
        sqlBf.append("delete from auto_flow_node_info where uuid in (");
        for (int i = 0; i < ids.size(); i++) {
            sqlBf.append("?,");
        }
        sqlBf.deleteCharAt(sqlBf.length() - 1);
        sqlBf.append(")");
        List<Object> params = new ArrayList<>();
        params.addAll(ids);

        DatabaseUtils.execSql(params, sqlBf.toString(), Integer.class);
        return true;
    }

    @Override
    public NodeInfoPo getById(String id) {
        List<Object> params = new ArrayList<>();
        StringBuffer sqlBf = new StringBuffer();
        sqlBf.append("select * from auto_flow_node_info where 1=1 and uuid = ?");
        params.add(id);
        NodeInfoPo nodeInfoPo = DatabaseUtils.execQueryOneSql(params, sqlBf.toString(), NodeInfoPo.class);
        return nodeInfoPo;
    }

    @Override
    public List<NodeInfoPo> list(String nodeName, String groupId, Integer whetherEnable) {
        List<Object> params = new ArrayList<>();
        StringBuffer sqlBf = new StringBuffer();
        sqlBf.append("select * from auto_flow_node_info where 1=1 ");
        if (StringUtils.isNotBlank(nodeName)) {
            sqlBf.append("and node_name like ? ");
            params.add("%" + nodeName + "%");
        }
        if (StringUtils.isNotBlank(groupId)) {
            sqlBf.append(" and group_id >= ? ");
            params.add(groupId);
        }
        if (whetherEnable != null) {
            sqlBf.append(" and whether_enable >= ? ");
            params.add(whetherEnable);
        }
        sqlBf.append(" order by sort_index asc, create_time desc ");
        List<NodeInfoPo> nodeInfoPos = DatabaseUtils.execQueryListSql(params, sqlBf.toString(), NodeInfoPo.class);
        return nodeInfoPos;
    }
}
